from django_simpleaggregation import Aggregate
from django_simpleaggregation.utils import smart_getattr
from django.contrib.contenttypes.models import ContentType
from django import template

register = template.Library()

class AggregateDataNode(template.Node):
    """
    Handles the initialization and display for the get_aggregate tag.
    """
    def __init__(self, model_or_iterable=None, unique_field=None, var_name=None):
        self.model_or_iterable = model_or_iterable
        if unique_field:
            self.unique_field = unique_field.replace('"', '')
        else:
            self.unique_field = unique_field
        self.var_name = var_name

    def render(self, context):
        try:
            model_or_iterable = template.resolve_variable(self.model_or_iterable, context)
            # If model_or_iterable is an iterable, take the first value.
            # This is simply to make writing templates easier so xxx_set.all
            # can be easily passed in to get_aggregate.
            if hasattr(model_or_iterable, '__iter__'):
                model = None
                for tmp in model_or_iterable:
                    model = tmp
                    break
            else:
                model = model_or_iterable
            content_type = ContentType.objects.get_for_model(model.__class__)
            get_kwargs = {
                'content_type' : content_type,
                'unique_field' : self.unique_field,
                'unique_field_data' : smart_getattr(model, self.unique_field)
            }
            try:
                agg = Aggregate.objects.get(**get_kwargs)
                context[self.var_name] = agg
            except Aggregate.DoesNotExist:
                pass
        # Fail silently
        except:
            pass
        return ''

def do_get_aggregate(parser, token):
    """
    Parses the template for get_aggregate tags, which 
    can take arguments of two forms:
    1. {% get_aggregate model unique_field as name %}
    2. {% get_aggregate iterable unique_field as name %}
    
    In the second instance, the first value of the iterable is
    taken, and the rest are discarded.  This should work flawlessly
    with QuerySets, as those can only contain one model type, but
    when using this with a list or another type of iterable, caution
    is warranted.
    """
    bits = list(token.split_contents())
    if len(bits) != 5 or bits[-2] != "as":
        raise template.TemplateSyntaxError, "%r expected format is 'model/iterable unique_field as name'" % bits[0]
    return AggregateDataNode(model_or_iterable = bits[1], unique_field = bits[2], var_name = bits[4])

register.tag('get_aggregate', do_get_aggregate)